/*
 * 使用函数指针
 * func_ptr（函数指针）
 */
#include <stdio.h>
#include <string.h>
#include <ctype.h> //为大小写转换函数提供原型

char showmenu(void);
void eatline(void); //读至行末
void show(void (*fp)(char *), char *str);
void ToUpper(char *);   //把字符串转换为大写
void ToLower(char *);   //把字符串转换为小写
void Transpose(char *); //大小写转置
void Nochange(char *);  //不改变字符串
void (*pfun)(char *);   //指向一个函数，该函数接受一个char*参数，并且没有返回值

int main()
{
    char line[81];
    char copy[81];
    char choice;

    puts("Enter a string:\n");
    while (gets(line) != NULL && line[0] != '\0')
    {
        while ((choice = showmenu()) != 'n')
        {
            switch (choice)
            {
            case 'u':
                pfun = ToUpper; //函数指针pfun 保存着 ToUpper函数的地址
                break;
            case 'l':
                pfun = ToLower;
                break;
            case 't':
                pfun = Transpose;
                break;
            case 'o':
                pfun = Nochange;
                break;
            }
            strcpy(copy, line); //为show()制作一份拷贝
            show(pfun, copy);   //使用用户选择的函数 (*fp)(str) == pfun(str) == ToUpper(str)
        }
        puts("Enter a string:\n");
    }
    return 0;
}

char showmenu(void)
{
    char ans;
    puts("Enter menu choice:\n");
    puts("u)  ToUpper      l)  ToLower");
    puts("t)  Transpose    o)  Nochange");
    puts("n)  Nextstring\n");

    ans = getchar();    //获得输入字符
    ans = tolower(ans); //把输入字符转换为小写字符
    eatline();          //剔除行中剩余部分

    while (strchr("ulton", ans) == NULL) //查找输入的字符中是否含有 u l t o n  这些字符，查找成功，返回字符首次出现的指针，查找不到返回NULL
    {
        puts("please input a u,l,t,o,or n:"); //意思是如果输入的不是以上这些字符，则输出这句话
        ans = tolower(getchar());
        eatline();
    }
    return ans;
}

void eatline(void) //循环读取并丢弃输入。while循环入口条件要执行一次，所以结果只保留第一个字符
{
    while (getchar() != '\n') //如果按回车，则不执行此函数
        continue;             //作为占位符，效果与  " ; " 一样。
}

void show(void (*fp)(char *), char *str) //函数指针作为参数
{
    (*fp)(str); //把用户选择的函数作用于str
    puts(str);  //显示结果
}

void ToUpper(char *str)
{
    while (*str)
    {
        *str = toupper(*str);
        str++;
    }
}

void ToLower(char *str)
{
    while (*str)
    {
        *str = tolower(*str);
        str++;
    }
}

void Transpose(char *str)
{
    while (*str)
    {
        if (islower(*str))
            *str = toupper(*str); //如果是小写的字符，就转换为大写
        else if (isupper(*str))
            *str = tolower(*str);
        str++;
    }
}

void Nochange(char *str)
{
    //不改变字符
}
